﻿using DocBot.Objects;
using DocBot.Util.Collections;
using DocBot.ViewModel;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using YT = Google.Apis.YouTube.v3.Data;

namespace DocBot.Util.Service
{
	public class YoutubeAPI
	{
		#region Add
		public bool AddSongToPlaylist(string songId, string playlistId, MainWindow window)
		{
			bool isSuccessfullyAdded = false;
			LogViewModel _log = (LogViewModel)window.FindResource("LogModel");
			try
			{
				this.AddSongToPlaylistAsync(songId, playlistId).Wait();
				isSuccessfullyAdded = true;
			}
			catch (AggregateException ex)
			{
				foreach (var e in ex.InnerExceptions)
				{
					Messenger.Instance.Messages.Enqueue(new Message(e.Message, MessageType.Log));
					isSuccessfullyAdded = false;
				}
			}

			return isSuccessfullyAdded;
		}

		private async Task AddSongToPlaylistAsync(string songId, string playlistId)
		{
			var youtubeService = await this.GetYouTubeService();
			var newPlaylistItem = new YT.PlaylistItem();
			newPlaylistItem.Snippet = new YT.PlaylistItemSnippet();
			newPlaylistItem.Snippet.PlaylistId = playlistId;
			newPlaylistItem.Snippet.ResourceId = new YT.ResourceId();
			newPlaylistItem.Snippet.ResourceId.Kind = "youtube#video";
			newPlaylistItem.Snippet.ResourceId.VideoId = songId;
			newPlaylistItem = await youtubeService.PlaylistItems.Insert(newPlaylistItem, "snippet").ExecuteAsync();
		}
		#endregion

		#region Remove
		public bool RemoveSongFromPlaylist(string playlistItemId, MainWindow window)
		{
			bool isSuccessfullyRemoved = false;
			try
			{
				this.RemoveSongFromPlaylistAsync(playlistItemId).Wait();
				isSuccessfullyRemoved = true;
			}
			catch (AggregateException ex)
			{
				foreach (var e in ex.InnerExceptions)
				{
					Messenger.Instance.Messages.Enqueue(new Message(e.Message, MessageType.Log));
					isSuccessfullyRemoved = false;
				}
			}

			return isSuccessfullyRemoved;
		}

		private async Task RemoveSongFromPlaylistAsync(string playlistItemId)
		{
			var youtubeService = await this.GetYouTubeService();
			PlaylistItemsResource.DeleteRequest deleteRequest = youtubeService.PlaylistItems.Delete(playlistItemId);
			string result = await deleteRequest.ExecuteAsync();
		}

		public List<PlaylistItem> GetPlayListSongs(string playListId)
		{
			List<PlaylistItem> playListSongs = new List<PlaylistItem>();
			try
			{
				this.GetPlayListSongsInternalAsync(playListId, playListSongs).Wait();
				Messenger.Instance.Messages.Enqueue(new Message("The Playlist contains " + playListSongs.Count + " Items", MessageType.LogAndChat));
				foreach (PlaylistItem p in playListSongs)
					return playListSongs;
			}
			catch (AggregateException ex)
			{
				foreach (var e in ex.InnerExceptions)
				{
					Messenger.Instance.Messages.Enqueue(new Message(e.Message, MessageType.Log));
				}
			}
			return null;
		}
		#endregion

		#region Get
		public async Task GetPlayListSongsInternalAsync(string playListId, List<PlaylistItem> playListSongs)
		{
			var youtubeService = await this.GetYouTubeService();

			var channelsListRequest = youtubeService.Channels.List("contentDetails");
			channelsListRequest.Mine = false;
			var nextPageToken = "";
			while (nextPageToken != null)
			{
				PlaylistItemsResource.ListRequest listRequest = youtubeService.PlaylistItems.List("snippet");
				listRequest.MaxResults = 50;
				listRequest.PlaylistId = playListId;
				listRequest.PageToken = nextPageToken;
				var response = await listRequest.ExecuteAsync();
				if (playListSongs == null)
				{
					playListSongs = new List<PlaylistItem>();
				}
				foreach (var playlistItem in response.Items)
				{
					Console.WriteLine("{0} ({1})", playlistItem.Snippet.Title, playlistItem.Snippet.ResourceId.VideoId);
					PlaylistItem currentSong = new PlaylistItem
						{
							SongTitle = playlistItem.Snippet.Title,
							Url = "https://www.youtube.com/watch?v=" + playlistItem.Snippet.ResourceId.VideoId,
							ArtistName = playlistItem.Snippet.ChannelTitle

						};
					playListSongs.Add(currentSong);

				}
				nextPageToken = response.NextPageToken;
			}
		}
		#endregion

		private async Task<YouTubeService> GetYouTubeService()
		{
			if (Settings.Instance.Youtube_API_JSON == String.Empty) return null;
			if (Settings.Instance.Youtube_Mail == String.Empty) return null;

			string userEmail = Settings.Instance.Youtube_Mail;
			UserCredential credential;

			using (var stream = new FileStream(Settings.Instance.Youtube_API_JSON, FileMode.Open, FileAccess.Read))
			{
				credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
					GoogleClientSecrets.Load(stream).Secrets,
					new[]
            {
                YouTubeService.Scope.Youtube
            },
					"user",
					CancellationToken.None,
					new FileDataStore(this.GetType().ToString()));
			}

			var youtubeService = new YouTubeService(new BaseClientService.Initializer()
			{
				HttpClientInitializer = credential,
				ApplicationName = this.GetType().ToString()
			});

			return youtubeService;
		}
	}

	public class DurationParser
	{
		private readonly string durationRegexExpression = @"PT(?<minutes>[0-9]{0,})M(?<seconds>[0-9]{0,})S";

		public ulong? GetDuration(string durationStr)
		{
			ulong? durationResult = default(ulong?);
			Regex regexNamespaceInitializations = new Regex(durationRegexExpression, RegexOptions.None);
			Match m = regexNamespaceInitializations.Match(durationStr);
			if (m.Success)
			{
				string minutesStr = m.Groups["minutes"].Value;
				string secondsStr = m.Groups["seconds"].Value;
				int minutes = int.Parse(minutesStr);
				int seconds = int.Parse(secondsStr);
				TimeSpan duration = new TimeSpan(0, minutes, seconds);
				durationResult = (ulong)duration.Ticks;
			}
			return durationResult;
		}
	}

}
